{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-aria/radio';
import hiddenDocs from 'docs:@react-aria/visually-hidden';
import focusDocs from 'docs:@react-aria/focus';
import statelyDocs from 'docs:@react-stately/radio';
import {HeaderInfo, FunctionAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-aria/radio/package.json';
import Anatomy from './anatomy.svg';
import {ExampleCard} from '@react-spectrum/docs/src/ExampleCard';
import buttongroupPreview from 'url:./buttongroup-example.png';
import cardPreview from 'url:./card-example.png';
import swatchPreview from 'url:./swatch-example.png';

---
category: Forms
keywords: [radiobutton, radio, input, aria]
---

# useRadioGroup

<PageDescription>{docs.exports.useRadioGroup.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['useRadioGroup', 'useRadio']}
  sourceData={[
    {type: 'W3C', url: 'https://www.w3.org/WAI/ARIA/apg/patterns/radiobutton/'}
  ]} />

## API

<FunctionAPI function={docs.exports.useRadioGroup} links={docs.links} />
<FunctionAPI function={docs.exports.useRadio} links={docs.links} />

## Features

Radio groups can be built in HTML with the
[&lt;fieldset&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset)
and [&lt;input&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) elements,
however these can be difficult to style. `useRadioGroup` and `useRadio` help achieve accessible
radio groups that can be styled as needed.

* Radio groups are exposed to assistive technology via ARIA
* Each radio is built with a native HTML `<input>` element, which can be optionally visually
  hidden to allow custom styling
* Full support for browser features like form autofill and validation
* Keyboard focus management and cross browser normalization
* Group and radio labeling support for assistive technology

## Anatomy

<Anatomy />

A radio group consists of a set of radio buttons, and a label. Each radio
includes a label and a visual selection indicator. A single radio button
within the group can be selected at a time. Users may click or touch a radio
button to select it, or use the <Keyboard>Tab</Keyboard> key to navigate to the group, the arrow keys
to navigate within the group, and the <Keyboard>Space</Keyboard> key to select an option.

`useRadioGroup` returns props for the group and its label, which you should spread
onto the appropriate element:

<TypeContext.Provider value={docs.links}>
  <InterfaceType properties={docs.links[docs.exports.useRadioGroup.return.id].properties} />
</TypeContext.Provider>

`useRadio` returns props for an individual radio, along with states that can be used for styling:

<TypeContext.Provider value={docs.links}>
  <InterfaceType properties={docs.links[docs.exports.useRadio.return.id].properties} />
</TypeContext.Provider>

Selection state is managed by the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.useRadioGroupState} />
hook in `@react-stately/radio`. The state object should be passed as an option to `useRadio`.

Individual radio buttons must have a visual label. If the radio group does not have a visible label,
an `aria-label` or `aria-labelledby` prop must be passed instead to identify the element to assistive
technology.

## Example

This example uses native input elements for the radios, and React context to share state from the group
to each radio. An HTML `<label>` element wraps the native input and the text to provide an implicit label
for the radio.

```tsx example
import {useRadioGroup, useRadio} from '@react-aria/radio';
import {useRadioGroupState} from '@react-stately/radio';

let RadioContext = React.createContext(null);

function RadioGroup(props) {
  let {children, label, description, errorMessage} = props;
  let state = useRadioGroupState(props);
  let {radioGroupProps, labelProps, descriptionProps, errorMessageProps} = useRadioGroup(props, state);

  return (
    <div {...radioGroupProps}>
      <span {...labelProps}>{label}</span>
      <RadioContext.Provider value={state}>
        {children}
      </RadioContext.Provider>
      {description && <div {...descriptionProps} style={{fontSize: 12}}>{description}</div>}
      {errorMessage && state.isInvalid &&
        <div {...errorMessageProps} style={{color: 'red', fontSize: 12}}>{errorMessage}</div>
      }
    </div>
  )
}

function Radio(props) {
  let {children} = props;
  let state = React.useContext(RadioContext);
  let ref = React.useRef(null);
  let {inputProps} = useRadio(props, state, ref);

  return (
    <label style={{display: 'block'}}>
      <input {...inputProps} ref={ref} />
      {children}
    </label>
  );
}

<RadioGroup label="Favorite pet">
  <Radio value="dogs">Dogs</Radio>
  <Radio value="cats">Cats</Radio>
</RadioGroup>
```

## Styling

To build a custom styled radio button, you can make the native input element visually hidden.
This is possible using the &lt;<TypeLink links={hiddenDocs.links} type={hiddenDocs.exports.VisuallyHidden} />&gt;
utility component from `@react-aria/visually-hidden`. It is still in the DOM and accessible to
assistive technology, but invisible. This example uses SVG to build the visual radio button,
which is hidden from screen readers with `aria-hidden`.

For keyboard accessibility, a focus ring is important to indicate which element has keyboard focus.
This is implemented with the <TypeLink links={focusDocs.links} type={focusDocs.exports.useFocusRing} />
hook from `@react-aria/focus`. When `isFocusVisible` is true, an extra SVG element is rendered to
indicate focus. The focus ring is only visible when the user is interacting with a keyboard,
not with a mouse or touch.

```tsx example export=true
import {VisuallyHidden} from '@react-aria/visually-hidden';
import {useFocusRing} from '@react-aria/focus';

// RadioGroup is the same as in the previous example
let RadioContext = React.createContext(null);

function RadioGroup(props) {
  let {children, label, description} = props;
  let state = useRadioGroupState(props);
  let {radioGroupProps, labelProps, descriptionProps, errorMessageProps, isInvalid, validationErrors} = useRadioGroup(props, state);

  return (
    <div {...radioGroupProps}>
      <span {...labelProps}>{label}</span>
      <RadioContext.Provider value={state}>
        {children}
      </RadioContext.Provider>
      {description && <div {...descriptionProps} style={{fontSize: 12}}>{description}</div>}
      {isInvalid &&
        <div {...errorMessageProps} style={{color: 'red', fontSize: 12}}>{validationErrors.join(' ')}</div>
      }
    </div>
  )
}

function Radio(props) {
  let {children} = props;
  let state = React.useContext(RadioContext);
  let ref = React.useRef(null);
  let {inputProps, isSelected, isDisabled} = useRadio(props, state, ref);
  let {isFocusVisible, focusProps} = useFocusRing();
  let strokeWidth = isSelected ? 6 : 2;

  return (
    <label style={{display: 'flex', alignItems: 'center', opacity: isDisabled ? 0.4 : 1}}>
      <VisuallyHidden>
        <input {...inputProps} {...focusProps} ref={ref} />
      </VisuallyHidden>
      <svg
        width={24}
        height={24}
        aria-hidden="true"
        style={{marginRight: 4}}>
        <circle
          cx={12}
          cy={12}
          r={8 - strokeWidth / 2}
          fill="none"
          stroke={isSelected ? 'orange' : 'gray'}
          strokeWidth={strokeWidth} />
        {isFocusVisible &&
          <circle
            cx={12}
            cy={12}
            r={11}
            fill="none"
            stroke="orange"
            strokeWidth={2} />
        }
      </svg>
      {children}
    </label>
  );
}

<RadioGroup label="Favorite pet">
  <Radio value="dogs">Dogs</Radio>
  <Radio value="cats">Cats</Radio>
</RadioGroup>
```

## Styled examples

<ExampleCard
  url="https://codesandbox.io/s/bold-wood-pxm478?file=/src/SwatchGroup.tsx"
  preview={swatchPreview}
  title="Swatch Group"
  description="A color swatch picker built with Tailwind CSS." />

<ExampleCard
  url="https://codesandbox.io/s/recursing-night-pu6w2g?file=/src/CardGroup.tsx"
  preview={cardPreview}
  title="Selectable Cards"
  description="A selectable card group built with Styled Components." />

<ExampleCard
  url="https://codesandbox.io/s/epic-faraday-qoiy0l?file=/src/ButtonGroup.js"
  preview={buttongroupPreview}
  title="Button Group"
  description="A single-selectable segmented button group." />

## Usage

The following examples show how to use the `RadioGroup` component created in the above example.

### Default value

An initial, uncontrolled value can be provided to the RadioGroup using the `defaultValue` prop, which accepts a value corresponding with the `value` prop of each Radio.

```tsx example
<RadioGroup label="Are you a wizard?" defaultValue="yes">
  <Radio value="yes">Yes</Radio>
  <Radio value="no">No</Radio>
</RadioGroup>
```

### Controlled value

A controlled value can be provided using the `value` prop, which accepts a value corresponding with the `value` prop of each Radio.
The `onChange` event is fired when the user selects a radio.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState(null);

  return (
    <>
      <RadioGroup label="Favorite avatar" value={selected} onChange={setSelected}>
        <Radio value="wizard">Wizard</Radio>
        <Radio value="dragon">Dragon</Radio>
      </RadioGroup>
      <p>You have selected: {selected}</p>
    </>
  );
}
```

### Description

The `description` prop can be used to associate additional help text with a radio group.

```tsx example
<RadioGroup label="Favorite pet" description="Select your favorite pet.">
  <Radio value="dogs">Dogs</Radio>
  <Radio value="cats">Cats</Radio>
</RadioGroup>
```

### Validation

RadioGroup supports the `isRequired` prop to ensure the user selects an option, as well as custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](../forms) guide to learn more.

When a RadioGroup has the `validationBehavior="native"` prop, validation errors block form submission. To display validation errors, use the `validationErrors` and `errorMessageProps` returned by `useRadioGroup`. This allows you to render error messages from all of the above sources with consistent custom styles.

```tsx example
<form>
  {/*- begin highlight -*/}
  <RadioGroup label="Favorite pet" name="pet" isRequired validationBehavior="native">
  {/*- end highlight -*/}
    <Radio value="dogs">Dog</Radio>
    <Radio value="cats">Cat</Radio>
    <Radio value="dragon">Dragon</Radio>
  </RadioGroup>
  <input type="submit" style={{marginTop: 8}} />
</form>
```

### Disabled

The entire RadioGroup can be disabled with the `isDisabled` prop.

```tsx example
<RadioGroup label="Favorite sport" isDisabled>
  <Radio value="soccer">Soccer</Radio>
  <Radio value="baseball">Baseball</Radio>
  <Radio value="basketball">Basketball</Radio>
</RadioGroup>
```

To disable an individual radio, pass `isDisabled` to the `Radio` instead.

```tsx example
<RadioGroup label="Favorite sport">
  <Radio value="soccer">Soccer</Radio>
  <Radio value="baseball" isDisabled>Baseball</Radio>
  <Radio value="basketball">Basketball</Radio>
</RadioGroup>
```

### Read only

The `isReadOnly` prop makes the selection immutable. Unlike `isDisabled`, the RadioGroup remains focusable.
See the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.

```tsx example
<RadioGroup label="Favorite avatar" defaultValue="wizard" isReadOnly>
  <Radio value="wizard">Wizard</Radio>
  <Radio value="dragon">Dragon</Radio>
</RadioGroup>
```

### HTML forms

RadioGroup supports the `name` prop, paired with the Radio `value` prop, for integration with HTML forms.

```tsx example
<RadioGroup label="Favorite pet" name="pet">
  <Radio value="dogs">Dogs</Radio>
  <Radio value="cats">Cats</Radio>
</RadioGroup>
```

## Internationalization

### RTL

In right-to-left languages, the radio group and radio buttons should be mirrored.
The group should be right-aligned, and the radio should be placed on the right
side of the label. Ensure that your CSS accounts for this.
